using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using HtmlAgilityPack;
using LastFmLib.API20.Artist;
using LastFmLib.API20.Types;
using LastFmLib.API20.User;
using StaffWars.Services;
using StaffWarsFm.Lib.Data;

namespace StaffWarsFm.Questions
{
    public class ArtistQuestionService : QuestionServiceBase
    {
        private Dictionary<User, IEnumerable<ArtistInfo>> _cache = new Dictionary<User, IEnumerable<ArtistInfo>>();

        private ScreenScrapingService _screenScraper = new ScreenScrapingService();

        [Question]
        public Question GetWikiQuestion(ArtistInfo artist)
        {
            var wikiUrl = GetWikiUrl(artist);
            var wiki = _screenScraper.GetElementByID(wikiUrl, "wiki");
            var artists = GetArtistsInWiki(wiki, wikiUrl);

            var questions = (from s in wiki.InnerText.Split('.', ',').Select(t => t.Trim())
                             let a = GetArtistInSentance(s, artists)
                             where false == string.IsNullOrEmpty(a)
                             select new
                             {
                                 Question = s.Replace(a, "Who") + "?",
                                 Answer = GetFullArtistName(a, artist.Name)
                             }).ToArray();

            if (0 == questions.Length)
            {
                throw new Exception(
                    "There once was a man from Nantucket. Whose cock was so long he could suck it. He said with a grin." +
                    "Wiping sperm from his chin. If my ear was a cunt I could Fuck it!"
                );
            }

            var question = questions[Util.Random(questions.Length)];

            return new Question
            {
                ImageUrl = "",
                Text = question.Question,
                Answers = GetAnswers(
                    question.Answer,
                    Cache<ArtistInfo>.Get(3, new ArtistInfo(question.Answer)).Select(a => a.Name),
                    a => new Answer
                    {
                        ImageUrl = "",
                        Text = a
                    }
                )
            };
        }

        [Question]
        public Question GetFactQuestion(ArtistInfo artist)
        {
            var wikiUrl = GetWikiUrl(artist);
            var factBox = _screenScraper.GetElementByClass(wikiUrl, "wikiFactBox");

            if (factBox.InnerText.Contains("No facts about this artist"))
            {
                throw new Exception("No facts about artists");
            }

            var factbox = _screenScraper.GetElementByClass(wikiUrl, "dl", "factbox");
            var labels = factbox.SelectNodes("dt");
            var facts = factbox.SelectNodes(@"dd/ul/li");
            var questions = new List<Question>();

            for (int i = 0; i < labels.Count; i++)
            {
                try
                {
                    questions.Add(new Question
                    {
                        ImageUrl = "",
                        Text = GetQuestion(labels[i].InnerText, artist.Name),
                        Answers = GetAnswers(
                            facts[i].InnerText.Trim(),
                            a => new Answer
                            {
                                Text = a,
                                ImageUrl = "",
                            }
                        )
                    });
                }
                catch (NotImplementedException)
                {
                    //mmmm, yummy exception
                }
            }

            if (0 == questions.Count)
            {
                throw new Exception(
                    "She stood on the bridge at midnight. Her lips all of a quiver. She gave a cough," +
                    "her leg fell off, and floated down the river"
                );
            }

            return questions[Util.Random(questions.Count)];
        }

        private string GetQuestion(string label, string artist)
        {
            switch (label.ToLower())
            {
                case "formed in":
                    return "What year did " + artist + " form?";
                case "split in":
                    return "What year did " + artist + " split?";
                case "reformed in":
                    return "What year did " + artist + " reform?";
                case "founded in":
                    return "Where did " + artist + " form?";
                default:
                    throw new NotImplementedException();
            }
        }

        private string GetFullArtistName(string artist, string mainArtist)
        {
            var artists = new List<string>(new[] { "He", "She", "They" }).Union(mainArtist.Split(' '));

            if (artists.Contains(artist))
            {
                return mainArtist;
            }

            return artist;
        }

        private IEnumerable<string> GetArtistsInWiki(HtmlNode wiki, string wikiUrl)
        {
            var artists = new List<string>(new[] { "He", "She", "They" });

            var artist = new Regex(@"music/(.*)/\+wiki").Match(wikiUrl).Groups[1].Value;

            artists.Add(artist.Replace('+', ' '));
            artists.AddRange(
                artist.Split('+')
            );

            var otherArtists = wiki.SelectNodes("a[@class='bbcode_artist']");

            if (null != otherArtists)
            {
                foreach (var node in otherArtists)
                {
                    artists.Add(node.InnerText);
                }
            }

            return artists.Distinct();
        }

        private string GetArtistInSentance(string sentance, IEnumerable<string> artists)
        {
            foreach (var artist in artists)
            {
                if (sentance.StartsWith(artist))
                {
                    return artist;
                }
            }
            return string.Empty;
        }

        private string GetWikiUrl(ArtistInfo artist)
        {
            return artist.Url + "/+wiki";
        }

        public ArtistInfo GetTopArtist(IEnumerable<User> players)
        {
            var artists = new List<ArtistInfo>();

            foreach (var user in players)
            {
                artists.AddRange(GetTopArtistsForUser(user).OrderBy(a => a.PlayCount));
            }

            return artists[Util.Random(artists.Count + 1)];
        }

        public IEnumerable<ArtistInfo> GetTopArtistsForUser(User user)
        {
            if (_cache.ContainsKey(user))
            {
                return _cache[user];
            }

            Cache<User>.Add(user);

            var getTopArtists = new UserGetTopArtists(
                user.UserName,
                LastFmLib.API20.modEnums.ChartPeriod.
                TwelveMonths
            );

            getTopArtists.AuthData = Util.GetAuthData();
            getTopArtists.Start();

            if (getTopArtists.Succeeded)
            {
                var artists = getTopArtists.Result.Where(a => a.HasMbId).Take(4).Select(a => GetArtistInfo(a.MbId));

                _cache[user] = artists;

                return artists;
            }

            throw new Exception("Mmmmm, beer");
        }

        public ArtistInfo GetArtistInfo(Guid mbId)
        {
            if (Cache<ArtistInfo>.Contains(a => a.MbId.ToString() == mbId.ToString()))
            {
                return Cache<ArtistInfo>.Get(a => a.MbId.ToString() == mbId.ToString()).First();
            }

            var getArtist = new ArtistGetInfo(mbId);

            getArtist.AuthData = Util.GetAuthData();
            getArtist.Start();

            if (getArtist.Succeeded)
            {
                Cache<ArtistInfo>.Add(getArtist.Result);

                return getArtist.Result;
            }

            throw new Exception(
                "There once was a man from East Kent, Whose tool was so long that it bent. To save her some trouble. He folded it double. And instead of coming...he went"
            );
        }
    }
}
